#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "pthread.h"

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include "BList.h"
#include "BVector.h"
#include "geometrics.h"
#include "quaternion.h"

#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "myglutaux.h"
#include "FTGLPolygonFont.h"
#include "AWLVP_DistanceMatrix.h"
#include "AWLocalViewport.h"
#include "AWLVP_NOOS3DProjection.h"

#include "AWEntity.h"
#include "AWMessage.h"
#include "AWBody.h"
#include "AWMsgMoveBody.h"
#include "AWNOOSCBBody.h"

#include "CaseBaseUtils.h"

#include "loader.h"


float r[19]={1,0,0,1,1,0,1,0.25F, 0.5,  0,  0,0.5,0.5,  0,0.5 ,0.75, 0.5,  1,  1};
float g[19]={0,1,0,1,0,1,1,0.25F,   0,0.5,  0,0.5,  0,0.5,0.5 ,0.75,   1,0.5,  1};
float b[19]={0,0,1,0,1,1,1,0.25F,   0,  0,0.5,  0,0.5,0.5,0.5 ,0.75,   1,  1,0.5};


AW_LVP_NOOS3DProjection::AW_LVP_NOOS3DProjection(int x,int y,int dx,int dy,NOOSDistanceMatrix *m,FeatureTerm **sel_ptr) : AW_LocalViewport(x,y,dx,dy)
{
	int i;
	int ncases=m->m_projection_cases.Length();
	List<FeatureTerm> summary_solution;
	FeatureTerm *solution;

	m_selected_ptr=sel_ptr;

	m_matrix=m;

	m_projection_x=new float[ncases];
	m_projection_y=new float[ncases];
	m_projection_z=new float[ncases];
	m_projection_r=new float[ncases];
	m_projection_g=new float[ncases];
	m_projection_b=new float[ncases];

	for(i=0;i<ncases;i++) {
		m_projection_x[i]=-1.0F+float(rand()%2000)/1000.0F;
		m_projection_y[i]=-1.0F+float(rand()%2000)/1000.0F;
		m_projection_z[i]=-1.0F+float(rand()%2000)/1000.0F;

		solution=m_matrix->m_projection_solutions[i];
		if (summary_solution.Position(solution)==-1) summary_solution.Add(new FeatureTerm(solution));

		{
			int pos=summary_solution.Position(solution);	
			
			if (pos<19) {
				m_projection_r[i]=r[pos];
				m_projection_g[i]=g[pos];
				m_projection_b[i]=b[pos];
			} else {
				m_projection_r[i]=0;
				m_projection_g[i]=0;
				m_projection_b[i]=0;
			} /* if */ 
		}

	} /* for */ 

	m_rotation=false;
	m_rotation_angle=0;
	m_selected_ft=0;

	m_font=0;

} /* AW_LVP_NOOS3DProjection::AW_LVP_NOOS3DProjection */ 


AW_LVP_NOOS3DProjection::~AW_LVP_NOOS3DProjection()
{
	m_matrix=0;
	m_selected_ft=0;

	if (m_projection_x!=0) delete m_projection_x;
	m_projection_x=0;
	if (m_projection_y!=0) delete m_projection_y;
	m_projection_y=0;
	if (m_projection_z!=0) delete m_projection_z;
	m_projection_z=0;

	if (m_projection_r!=0) delete m_projection_r;
	m_projection_r=0;
	if (m_projection_g!=0) delete m_projection_g;
	m_projection_g=0;
	if (m_projection_b!=0) delete m_projection_b;
	m_projection_b=0;

#ifndef KITSCHY_DEBUG_MEMORY 
	// I don't know why, but the memory_manager complains about this free:
	if (m_font!=0) delete m_font;
#endif
} /* AW_LVP_NOOS3DProjection::~AW_LVP_NOOS3DProjection */ 



void AW_LVP_NOOS3DProjection::draw_internal(void)
{
	float f=1.0F;
	int vpx=0,vpy=0,vpw=800,vph=600;

	if (m_font==0) {
		FILE *fp=fopen("arial.ttf","r");
		if (fp!=0) {
			fclose(fp);
			m_font=new FTGLPolygonFont("arial.ttf");
			m_font->FaceSize(2);
			m_font->Depth(0.2F);
		} /* if */ 
	} /* if */ 

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	{
		int tmp[4];
		glGetIntegerv(GL_VIEWPORT,tmp);
		vpx=tmp[0];
		vpy=tmp[1];
		vpw=tmp[2];
		vph=tmp[3];
		f=float(vpw)/float(vph);
	}


	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if (!m_matrix->is_finished()) {

		/* Draw a Progress bar: */ 
		glColor3f(1,1,1);
		glutSolidBox(0.98,0.25F,0.1F);
		glColor3f(0,0,0);
		glutSolidBox(0.96,0.23F,0.2F);
		glColor3f(1,1,1);
		glPushMatrix();
		{
			float f=m_matrix->get_progress();
			glTranslatef((1-f)*-0.94,0,0);
			glutSolidBox(f*0.94,0.21,0.3F);
		}
		glPopMatrix();

	} else {
		if (m_rotation) m_rotation_angle+=0.5F;

		{
			int i;
			for(i=0;i<2;i++) update_projection();
		}
		draw_projection();

		/* Rotation button: */ 
		{
			glPushName(1);
			glDisable(GL_DEPTH_TEST);
			glPushMatrix();
			glTranslatef(0.7F,-0.85F,0);
			glColor3f(0.4F,0.6F,1.0F);
			glutSolidBox(0.25F,0.1F,0.1F);
			glTranslatef(0,0,-0.2F);
			if (m_rotation) {
				if (m_font!=0) {
					float llx,lly,llz,urx,ury,urz;
					m_font->BBox( "Stop", llx, lly, llz, urx, ury, urz);		
					glPushMatrix();
					glScalef(0.05F,0.05F,0.05F);
					glTranslatef(-(urx-llx)/2,-0.5F,0);
					glColor3f(1,1,1);
					m_font->Render("Stop");
					glPopMatrix();
				} /* if */ 
			} else {
				if (m_font!=0) {
					float llx,lly,llz,urx,ury,urz;
					m_font->BBox( "Rotate", llx, lly, llz, urx, ury, urz);		
					glPushMatrix();
					glScalef(0.05F,0.05F,0.05F);
					glTranslatef(-(urx-llx)/2,-0.5F,0);
					glColor3f(1,1,1);
					m_font->Render("Rotate");
					glPopMatrix();
				} /* if */ 
			} /* if */ 
			glPopMatrix();
			glEnable(GL_DEPTH_TEST);
			glPopName();
		}
	} /* if */ 

	glPopMatrix();

} /* AW_LVP_NOOS3DProjection::draw_internal */ 


void AW_LVP_NOOS3DProjection::update_projection(void)
{
	int ncases=m_matrix->m_projection_cases.Length();
	int i,j;
	float d,projection_d;
	float nx,ny,nz;
	float difx,dify,difz;
	float factor=0.2F;
	float avg_x,avg_y,avg_z;

	/* execute n iterations only: */ 
	avg_x=0;
	avg_y=0;
	avg_z=0;
	for(i=0;i<ncases;i++) {
		nx=0;
		ny=0;
		nz=0;
		for(j=0;j<ncases;j++) {
			d=m_matrix->m_projection_matrix[j+i*ncases];
			difx=m_projection_x[i]-m_projection_x[j];
			dify=m_projection_y[i]-m_projection_y[j];
			difz=m_projection_z[i]-m_projection_z[j];

			projection_d=float(sqrt(difx*difx+dify*dify+difz*difz));

			if (projection_d>0) {
				float m=(d-projection_d)*(d-projection_d);
				if ((d-projection_d)<0) m=-m;
				nx+=m*(difx/projection_d);
				ny+=m*(dify/projection_d);
				nz+=m*(difz/projection_d);
			} else {
				nx+=(d-projection_d)*((rand()%100)/100.0F);
				ny+=(d-projection_d)*((rand()%100)/100.0F);
				nz+=(d-projection_d)*((rand()%100)/100.0F);
			} /* if */ 
		} /* for */ 

		nx/=ncases;
		ny/=ncases;
		nz/=ncases;

		m_projection_x[i]+=nx*factor;
		m_projection_y[i]+=ny*factor;
		m_projection_z[i]+=nz*factor;

		avg_x+=m_projection_x[i];
		avg_y+=m_projection_y[i];
		avg_z+=m_projection_z[i];
	} /* for */ 

	avg_x/=ncases;
	avg_y/=ncases;
	avg_z/=ncases;

	for(i=0;i<ncases;i++) {
		m_projection_x[i]-=avg_x;
		m_projection_y[i]-=avg_y;
		m_projection_z[i]-=avg_z;
	} /* for */ 
} /* AW_LVP_NOOS3DProjection::update_projection */ 



void AW_LVP_NOOS3DProjection::draw_projection(void)
{
	int i;
	int ncases=m_matrix->m_projection_cases.Length();
	float maximum=0;

	for(i=0;i<ncases;i++) {
		if (m_projection_x[i]>maximum) maximum=m_projection_x[i];
		if (-m_projection_x[i]>maximum) maximum=-m_projection_x[i];
		if (m_projection_y[i]>maximum) maximum=m_projection_y[i];
		if (-m_projection_y[i]>maximum) maximum=-m_projection_y[i];
		if (m_projection_z[i]>maximum) maximum=m_projection_z[i];
		if (-m_projection_z[i]>maximum) maximum=-m_projection_z[i];
	} /* for */ 

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();

	{
		float fAspect;
		GLint viewport[4];		

		glGetIntegerv(GL_VIEWPORT, viewport);	

		if (viewport[3]!=0) fAspect = (GLfloat)viewport[2]/viewport[3];
					   else fAspect = 1.0f;		
//		glLoadIdentity();
		gluPerspective(45.0f, fAspect, 0.1F, 100);
		gluLookAt(0,0,-10, 0,0,0, 0,-1,0);

		glMatrixMode(GL_MODELVIEW);

		glPushMatrix();
		if (maximum>0) glScalef(3/maximum,3/maximum,3/maximum);
		glRotatef(m_rotation_angle,0,1,0);

		for(i=0;i<ncases;i++) {
			glPushMatrix();

			glColor3f(m_projection_r[i],m_projection_g[i],m_projection_b[i]);
			glTranslatef(m_projection_x[i],m_projection_y[i],m_projection_z[i]);
			glPushName(i+2);
			if (m_selected_ft!=0 && 
				m_selected_ft==m_matrix->m_projection_cases[i]) {
				glutSolidSphere(0.05F*maximum,8,8);
			} else {
				glutSolidSphere(0.03F*maximum,8,8);
			} /* if */ 
			glPopName();
			glPopMatrix();
		} /* for */ 
	
		glPopMatrix();
	}

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);

} /* AW_LVP_NOOS3DProjection::draw_projection */ 



bool AW_LVP_NOOS3DProjection::MouseClick_internal(int selected)
{

	switch(selected) {
	case 1: if (m_rotation) m_rotation=false;
					   else m_rotation=true;
			break;
	default:
			if (selected>=2) {
				if (m_selected_ft==m_matrix->m_projection_cases[selected-2]) {
					m_selected_ft=0;
				} else {
					m_selected_ft=m_matrix->m_projection_cases[selected-2];
					*m_selected_ptr=m_selected_ft;
				} /* if */ 
			} /* if */ 
	} /* switch */ 
	
	return true;
} /* AW_LVP_NOOS3DProjection::MouseClick */ 